package com.xqboss.apps.service.marketing;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Pair;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.xqboss.apps.constant.LockKey;
import com.xqboss.apps.domain.box.Box;
import com.xqboss.apps.domain.box.BoxNft;
import com.xqboss.apps.domain.marketing.MarketingAirdrop;
import com.xqboss.apps.domain.marketing.MarketingAirdropRecord;
import com.xqboss.apps.domain.member.SysUserNft;
import com.xqboss.apps.domain.nft.Nft;
import com.xqboss.apps.domain.nft.NftNumber;
import com.xqboss.apps.dto.marketing.AppGetAirdropListDto;
import com.xqboss.apps.dto.marketing.GetAirdropRecordListDto;
import com.xqboss.apps.enums.box.BoxSequenceEnum;
import com.xqboss.apps.enums.marketing.AirdropStatusEnum;
import com.xqboss.apps.enums.nft.NftTypeEnum;
import com.xqboss.apps.mapper.marketing.MarketingAirdropRecordMapper;
import com.xqboss.apps.service.box.BoxService;
import com.xqboss.apps.service.nft.NftNumberService;
import com.xqboss.apps.service.nft.NftService;
import com.xqboss.apps.service.user.UserBoxService;
import com.xqboss.apps.vo.marketing.AirdropRecordExportVo;
import com.xqboss.apps.vo.marketing.AirdropRecordVo;
import com.xqboss.apps.vo.marketing.AppAirdropRecord2Vo;
import com.xqboss.apps.vo.marketing.AppAirdropRecordVo;
import com.xqboss.common.constant.HttpStatus;
import com.xqboss.common.core.redis.lock.LockObject;
import com.xqboss.common.core.redis.lock.RedisLock;
import com.xqboss.common.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

/**
 * @author Trent
 * @date 2023/9/1
 */
@Service
public class AirdropRecordService extends ServiceImpl<MarketingAirdropRecordMapper, MarketingAirdropRecord> {

    @Autowired
    private NftService nftService;

    @Autowired
    private NftNumberService nftNumberService;

    @Autowired
    private UserBoxService userBoxService;

    @Autowired
    private BoxService boxService;

    /**
     * 删除空投的用户空投记录
     * @param airdropId 空投ID
     */
    public void removeByAirdropId(Long airdropId) {
        boolean removed = remove(new LambdaQueryWrapper<MarketingAirdropRecord>()
                .eq(MarketingAirdropRecord::getAirdropId, airdropId));
        if(!removed){
            throw new ServiceException("操作失败！");
        }
    }

    /**
     * 获取空投的用户列表
     */
    public List<AirdropRecordVo> getRecordByAirdropId(GetAirdropRecordListDto params){
        return baseMapper.getRecordByAirdropId(params);
    }

    /**
     * 发放空投
     *
     * @param airdrop 空投记录
     * @param isRandom 藏品|装备的空投顺序（true-随机），注意：对箱子不生效
     */
    public void dispatchAirdrop(MarketingAirdrop airdrop,boolean isRandom){
        int page = 1;
        int size = 1000;
        while(true){
            Page<Object> pageStart = PageHelper.startPage(page, size);
            List<MarketingAirdropRecord> userList = baseMapper.selectList(new LambdaQueryWrapper<MarketingAirdropRecord>()
                    .eq(MarketingAirdropRecord::getAirdropId, airdrop.getId())
                    .eq(MarketingAirdropRecord::getAirdropStatus, AirdropStatusEnum.NORMAL));
            pageStart.close();
            for (MarketingAirdropRecord userAirdrop : userList) {
                dispatchAirdrop(userAirdrop, airdrop ,isRandom);
            }
            if(userList.size() < size){
                break;
            }
        }
    }

    /**
     * 发放空投
     * @param record
     * @param airdrop
     */
    @RedisLock(lockKey = LockKey.LOCK_USER_AIRDROP)
    @Transactional(rollbackFor = Exception.class)
    public void dispatchAirdrop(@LockObject(valueFields = "id") MarketingAirdropRecord record, MarketingAirdrop airdrop,boolean isRandom){
        record = getById(record.getId());
        if(record.getAirdropStatus() == AirdropStatusEnum.NORMAL){
            if(airdrop.getAirdropType() == NftTypeEnum.BOX){
                Box box = boxService.getById(airdrop.getSourceId());
                if(box == null){
                    throw new ServiceException("箱子不存在！");
                }
                // 扣除库存
                Map<BoxNft, Integer> boxNftIntegerMap = boxService.takeLockStore(airdrop.getSourceId(), airdrop.getQuantity(), null);
                Set<BoxNft> boxNfts = boxNftIntegerMap.keySet();
                List<Pair<BoxNft, List<NftNumber>>> nftList = new ArrayList<>();
                for (BoxNft boxNft : boxNfts) {
                    List<NftNumber> nftNumbers = nftNumberService.distributeBox(record.getUserId(), record.getId(), boxNft.getNftId(), boxNftIntegerMap.get(boxNft), box.getSequence() == BoxSequenceEnum.RANDOM);
                    nftList.add(new Pair<>(boxNft, nftNumbers));
                }
                userBoxService.addUserBox(record.getUserId(), airdrop.getId(), record.getId(), box, nftList, airdrop.getQuantity(), LocalDateTime.now());
            }else{
                List<SysUserNft> nftNumbers = nftNumberService.distributeAirdropNftNumber(airdrop, record, isRandom);
            }
            update(new LambdaUpdateWrapper<MarketingAirdropRecord>()
                    .set(MarketingAirdropRecord::getAirdropStatus, AirdropStatusEnum.COMPLETE)
                    .eq(MarketingAirdropRecord::getId, record.getId()));
        }
    }


    /**
     * 获取用户的空投记录
     * @param params
     * @return
     */
    public List<AppAirdropRecordVo> getUserRecord(AppGetAirdropListDto params) {
        return baseMapper.getUserRecordList(params);
    }

    /**
     * 获取用户空投详情
     * @param userId
     * @param airdropRecordId
     * @return
     */
    public AppAirdropRecordVo getUserRecord(Long userId, Long airdropRecordId) {
        AppAirdropRecordVo record = baseMapper.getUserRecordById(airdropRecordId);
        if(record == null || !Objects.equals(record.getUserId(), userId)){
            throw new ServiceException("资源不存在！");
        }
        return record;
    }

    public List<AppAirdropRecord2Vo> listV2(AppGetAirdropListDto params) {
        return baseMapper.listV2(params);
    }

    /**
     * 获取用户空投详情：V2
     * @param userId
     * @param airdropRecordId
     * @return
     */
    public AppAirdropRecord2Vo getUserRecordV2(Long userId, Long airdropRecordId) {
        AppAirdropRecord2Vo record = baseMapper.getUserRecordV2ById(airdropRecordId);
        if(record == null || !Objects.equals(record.getUserId(), userId)){
            throw new ServiceException("资源不存在！");
        }
        return record;
    }

    /**
     * 导出空投详情
     * @param params
     * @return
     */
    public List<AirdropRecordExportVo> export(GetAirdropRecordListDto params) {
        params.startOrder();
        params.setPageSize(null);
        List<AirdropRecordVo> voList = getRecordByAirdropId(params);
        List<AirdropRecordExportVo> res = BeanUtil.copyToList(voList, AirdropRecordExportVo.class);
        return res;
    }
}
